package com.stylefeng.guns.rest.modular.auth.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.exceptions.ClientException;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.stylefeng.guns.core.base.controller.BaseController;
import com.stylefeng.guns.core.cache.CacheKit;
import com.stylefeng.guns.core.util.AliMsgUtils;
import com.stylefeng.guns.core.util.HttpUtil;
import com.stylefeng.guns.core.util.MD5Util;
import com.stylefeng.guns.rest.Tools.CodeMsg;
import com.stylefeng.guns.rest.Tools.Result;
import com.stylefeng.guns.rest.Util.Md5Util;
import com.stylefeng.guns.rest.common.SystemProperties;
import com.stylefeng.guns.rest.common.annotion.SSO;
import com.stylefeng.guns.rest.common.exception.BizExceptionEnum;
import com.stylefeng.guns.rest.common.persistence.model.DriverInf;
import com.stylefeng.guns.rest.modular.DTO.DriverInfDTO;
import com.stylefeng.guns.rest.modular.auth.controller.dto.AuthRequest;
import com.stylefeng.guns.rest.modular.auth.converter.BaseTransferEntity;
import com.stylefeng.guns.rest.modular.auth.security.impl.Base64SecurityAction;
import com.stylefeng.guns.rest.modular.auth.util.JwtTokenUtil;
import com.stylefeng.guns.rest.modular.auth.validator.IDriverInfService;
import com.stylefeng.guns.rest.modular.auth.validator.IReqValidator;
import com.stylefeng.guns.rest.validater.Insert;
import com.stylefeng.guns.rest.validater.Search;
import com.stylefeng.guns.rest.validater.Update;
import com.stylefeng.guns.rest.validater.Verify;
import com.taobao.api.ApiException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.MediaType;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 请求验证的
 *
 * @author 张亚林
 * @Date 2018/11/12 14:22
 */
@RestController
@RequestMapping("/gunsApi/driver")
@Api(value = "司机端手机验证相关操作", tags = {"司机端手机验证相关操作"})
@Log4j2
public class AuthController extends BaseController {
    @Resource
    private IDriverInfService driverInfService;

    @Resource
    private JwtTokenUtil jwtTokenUtil;


    @Resource
    private SystemProperties systemProperties;

    private static final String TRANSFERCACHE = "CONSTANT";

    @Resource(name = "dbValidator")
    private IReqValidator reqValidator;


    @ApiOperation(value = "获取帮助中心电话", notes = "获取帮助中心电话", httpMethod = "POST")
    @PostMapping(value = "/getHelpCenter")
    @SSO
    public Result getHelpCenter() {
        Map<String, Object> map = new LinkedHashMap<>();
        CodeMsg codeMsg = CodeMsg.REQUEST_SUCESS;
        map.put("helpCener", systemProperties.getHelpCenter());
        map.putAll(BeanUtil.beanToMap(codeMsg));
        return Result.success(map);
    }

    @ApiOperation(value = "获取短信登录验证码", notes = "获取短信登录验证码", httpMethod = "POST")
    @PostMapping(value = "/getVerifyCode")
    public Result getVerifyCode(@Validated(value = Search.class) @RequestBody AuthRequest authRequest, BindingResult result) throws ApiException {
        Map<String, Object> map = new LinkedHashMap<>();
        if (result.hasErrors()) {
            CodeMsg codeMsg = CodeMsg.BIND_ERROR;
            map.putAll(BeanUtil.beanToMap(codeMsg));
            return Result.error("参数校验异常,必填参数不能为空!", 500101);
        }
        String user = authRequest.getUserName();
        String random = RandomUtil.randomNumbers(4);
        AliMsgUtils.sendDySms(user, random);
        CacheKit.put(TRANSFERCACHE, "code_" + user, random);
        log.info("获取到司机端验证码{}成功!", random);
        return Result.success("获取短信验证码成功!");
    }

    @ApiOperation(value = "获取司机信息", notes = "获取司机信息", httpMethod = "POST")
    @PostMapping(value = "/getDriverInfo")
    @SSO
    public Result getDriverInfo() {
        String token = this.getHttpServletRequest().getHeader("Authorization").substring(7);
        String user = jwtTokenUtil.getUsernameFromToken(token);
        Wrapper<DriverInf> wrapper = new EntityWrapper<>();
        wrapper.eq("di_phone", user);
        DriverInf driverInf = this.driverInfService.selectOne(wrapper);
        DriverInfDTO dto = new DriverInfDTO();
        if (driverInf != null) {
            BeanUtil.copyProperties(driverInf, dto);
            return Result.success(dto);
        }
        return Result.error("获取司机信息失败", 500102);
    }


    @ApiOperation(value = "司机登录验证", notes = "司机登录验证", httpMethod = "POST")
    @PostMapping(value = "${jwt.auth-path}")
    public Result createAuthenticationToken(@Validated(value = Verify.class) @RequestBody AuthRequest authRequest, BindingResult result) throws ClientException {
        Map<String, Object> map = new LinkedHashMap<>();
        DriverInf driverInf = null;
        String username = authRequest.getUserName();
        if (StringUtils.isNotBlank(username)) {
            EntityWrapper<DriverInf> wrapper = new EntityWrapper<>();
            wrapper.eq("di_phone", username);
            driverInf = this.driverInfService.selectOne(wrapper);
            if (driverInf == null) {
                return Result.error(CodeMsg.USER_NO_REG.getMessage(), 500103);
            }
        }

        if (result.hasErrors()) {
            return Result.error(CodeMsg.REQUEST_ERROR);
        }
        boolean validate = false;
        if (authRequest.getType().equals(0)) {
            validate = reqValidator.validate(authRequest);
        } else {//验证码登录
            String code = CacheKit.get(TRANSFERCACHE, "code_" + username);
            if (StringUtils.equals(code, authRequest.getPassword())) {
                validate = true;
            } else {
                CodeMsg codeMsg = CodeMsg.INVALID_KAPTCHA;
                map.putAll(BeanUtil.beanToMap(codeMsg));
                return Result.error(CodeMsg.REQUEST_ERROR.getMessage(), 500102);
            }
        }
        if (validate) {
            final String randomKey = jwtTokenUtil.getRandomKey();
            final String token = jwtTokenUtil.generateToken(authRequest.getUserName(), randomKey);
            String jsonString = JSON.toJSONString(authRequest);
            String encode = new Base64SecurityAction().doAction(jsonString);
            String md5 = MD5Util.encrypt(encode + randomKey);
            BaseTransferEntity baseTransferEntity = new BaseTransferEntity();
            baseTransferEntity.setObject(encode);
            baseTransferEntity.setSign(md5);
            CacheKit.put(TRANSFERCACHE, "randomKey_" + authRequest.getUserName(), randomKey);
            CacheKit.put(TRANSFERCACHE, "token_" + authRequest.getUserName(), token);
            CacheKit.put(TRANSFERCACHE, authRequest.getUserName(), driverInf);
            return Result.success(token);
        } else {
            return Result.error(BizExceptionEnum.AUTH_REQUEST_ERROR.getMessage(), 1003);
        }
    }

    @ApiOperation(value = "登录对象加密", notes = "登录对象加密", httpMethod = "POST")
    @PostMapping(value = "encrypt")
    @SSO
    public Result encrypt(@Validated(value = Update.class) AuthRequest authRequest, BindingResult result) {
        Map<String, Object> map = new LinkedHashMap<>();
        if (result.hasErrors()) {
            return Result.success(CodeMsg.REQUEST_ERROR.getMessage());
        }
        final String randomKey = CacheKit.get(TRANSFERCACHE, "randomKey_" + authRequest.getUserName());
        String jsonString = JSON.toJSONString(authRequest);
        String encode = new Base64SecurityAction().doAction(jsonString);
        String md5 = MD5Util.encrypt(encode + randomKey);
        BaseTransferEntity baseTransferEntity = new BaseTransferEntity();
        baseTransferEntity.setObject(encode);
        baseTransferEntity.setSign(md5);
        String obj = JSONUtil.toJsonStr(baseTransferEntity);
        return Result.success(obj);
    }

    @ApiOperation(value = "修改密码", notes = "司机端修改密码", httpMethod = "POST")
    @PostMapping(value = "modifyPass")
    public Result modifyPass(@Validated(value = Update.class) @RequestBody AuthRequest authRequest, BindingResult result) {
        String msg = "";
        Boolean bool = false;
        if (result.hasErrors()) {
            return Result.error(this.getErrors(result));
        }
        String phone = authRequest.getUserName();
        DriverInf newU = new DriverInf();
        newU.setDiPhone(phone);
        DriverInf driverInf = this.driverInfService.selectOne(new EntityWrapper<>(newU));
        if (driverInf == null) {
            CodeMsg codeMsg = CodeMsg.USER_NOT_EXSIST;
            return Result.error(codeMsg.getMessage());
        } else {
            if (authRequest.getType().equals(new Integer(0))) {//密码修改
                //验证老密码是否正确
                String passwd = authRequest.getPassword();
                passwd = Md5Util.md5(passwd, driverInf.getDiSalt());
                if (StringUtils.equals(passwd, driverInf.getDiPassword())) {
                    bool = true;
                } else {
                    msg = "密码输入有误!";
                }
            } else {//验证码修改
                String code = CacheKit.get(TRANSFERCACHE, "code_" + authRequest.getUserName());
                if (StringUtils.equals(code, authRequest.getPassword())) {
                    bool = true;
                } else {
                    msg = "验证码输入有误!";
                }
            }
            if (bool) {
                driverInf.setDiPassword(Md5Util.md5(authRequest.getNpasswd(), driverInf.getDiSalt()));
                driverInf.setDiCheckResult("1");
                Boolean b = driverInf.updateById();
                if (b) {
                    msg = "更新密码成功！";
                    return Result.success(msg);
                } else {
                    msg = "更新密码失败!";
                    return Result.error(msg, 1003);
                }
            } else {
                return Result.error(msg, 1003);
            }
        }
    }

    @ApiOperation(value = "找回密码", notes = "司机端找回密码", httpMethod = "POST")
    @PostMapping(value = "getPass")
    public Result getPass(@Validated(value = Update.class) @RequestBody AuthRequest authRequest, BindingResult result) {
        String msg = "";
        Boolean bool = false;
        if (result.hasErrors()) {
            return Result.error("请输入用户手机号!", 500101);
        }
        String phone = authRequest.getUserName();
        DriverInf newU = new DriverInf();
        newU.setDiPhone(phone);
        DriverInf driverInf = this.driverInfService.selectOne(new EntityWrapper<>(newU));
        if (driverInf == null) {
            CodeMsg codeMsg = CodeMsg.USER_NOT_EXSIST;
            return Result.error(codeMsg.getMessage(), 500102);
        } else {
            String code = CacheKit.get(TRANSFERCACHE, "code_" + authRequest.getUserName());
            if (StringUtils.equals(code, authRequest.getPassword())) {
                bool = true;
            } else {
                msg = "验证码输入有误!";
            }
        }
        if (bool) {
            driverInf.setDiPassword(Md5Util.md5(authRequest.getNpasswd(), driverInf.getDiSalt()));
            driverInf.setDiCheckResult("1");
            Boolean b = driverInf.updateById();
            if (b) {
                msg = "找回密码成功,请重新登录！";
                return Result.success(msg);
            } else {
                msg = "找回密码失败!";
                return Result.error(msg, 1003);
            }
        } else {
            return Result.error(msg, 1003);
        }
    }


    /**
     * 新增司机账号
     */
    @ApiOperation(value = "手机号注册", notes = "添加司机账号", httpMethod = "POST")
    @PostMapping(value = "/add", produces = MediaType.APPLICATION_JSON_UTF8_VALUE, consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public Result add(@Validated(value = Insert.class) @RequestBody DriverInf driverInf, BindingResult result) {
        Map<String, Object> map = new LinkedHashMap<>();
        if (result.hasErrors()) {
            CodeMsg codeMsg = CodeMsg.PARAMETER_ISNULL;
            return Result.error(codeMsg.getMessage());
        }
        // 完善账号信息
        // 判断账号是否重复
        DriverInf newU = new DriverInf();
        newU.setDiPhone(driverInf.getDiPhone());
        DriverInf exiDiver = this.driverInfService.selectOne(new EntityWrapper<>(newU));

        if (exiDiver != null) {
            CodeMsg codeMsg = CodeMsg.USER_ALREADY_REG;
            return Result.error(codeMsg.getMessage());
        }
        driverInf.setDiSalt(RandomUtil.randomString(8));
        // 添加用户  默认手机号后六位
        String passwd = driverInf.getDiPassword();
        if (StringUtils.isBlank(passwd))
            driverInf.setDiPassword(Md5Util.md5(StringUtils.substring(StringUtils.trimToNull(driverInf.getDiPhone()), -6), driverInf.getDiSalt()));
        else
            driverInf.setDiPassword(Md5Util.md5(StringUtils.trimToNull(passwd), driverInf.getDiSalt()));
        driverInf.setDiCheckResult("1");
        Boolean b = this.driverInfService.insert(driverInf);
        if (b) {
            CodeMsg codeMsg = CodeMsg.REQUEST_SUCESS;
            return Result.success(codeMsg.getMessage());
        } else {
            CodeMsg codeMsg = CodeMsg.REQUEST_ERROR;
            return Result.error(codeMsg.getMessage());
        }
    }

    private Map<String, String> getErrors(BindingResult result) {
        Map<String, String> map = new HashMap<String, String>();
        List<FieldError> list = result.getFieldErrors();
        for (FieldError error : list) {
            System.out.println("error.getField():" + error.getField());
            System.out.println("error.getDefaultMessage():" + error.getDefaultMessage());
            map.put(error.getField(), error.getDefaultMessage());
        }
        return map;
    }

    /**
     * 微信 code
     *
     * @param code 任务单ID
     * @return
     */
    @ApiOperation(value = "获取openId", notes = "获取openId", httpMethod = "POST")
    @PostMapping(value = "/getUserOpenId", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ResponseBody
    public Result getUserOpenId(
            @ApiParam(name = "code", value = "微信code", required = true) @RequestParam(value = "code") String code) {
        try {
            //微信基本配置
            String APPID = "wx493114f7781ece0f";
            String SECRET = "68a4ec56b8c0b76e2671b67311e83521";
            String GRANT_TYPE = "authorization_code";
            String WXURL = "https://api.weixin.qq.com/sns/oauth2/access_token";
            Map map = new HashMap();
            map.put("APPID", APPID);
            map.put("SECRET", SECRET);
            map.put("CODE", code);
            map.put("GRANT_TYPE", GRANT_TYPE);
            String response = HttpUtil.doGet(WXURL, map, "UTF-8");
            System.out.println(response);
            JSONObject json = JSON.parseObject(response);
            map.clear();
            if (json.containsKey("openid")) {
                map.put("OK", "OK");
                map.put("openId", json.getString("openid"));
            } else {

                map.put("OK", "error");
                map.put("message", "微信授权失败，请检查相关配置");
            }
            return Result.success(map);
        } catch (Exception e) {
            return Result.error(e.getMessage(), 500100);
        }
    }
}
